package client;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JComboBox;
import java.util.Vector;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.StringTokenizer;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JSlider;
import javax.swing.SwingUtilities;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import uk.co.caprica.vlcj.binding.LibVlcConst;
import uk.co.caprica.vlcj.player.MediaPlayer;
import uk.co.caprica.vlcj.player.MediaPlayerEventAdapter;
import uk.co.caprica.vlcj.player.embedded.EmbeddedMediaPlayer;

public class PlayerControlsPanel extends JPanel {

    private static String NEWVIDEO = "new";
    private static String TIMER = "timer";
    private static String POSITION = "position";
    private static String SPOSITION = "sposition";
    private static String PLAY = "play";
    private static String PAUSE = "pause";
    private static String STOP = "stop";
    private static String LENGTH = "length";
    private static String QUALITY = "quality";
    private static String OK = "ok";
    private static String QUIT = "quit";
    private static String ULQ = "240p";
    private static String LQ = "360p";
    private static String SQ = "480p";
    private static String HQ = "720p";
    private static final int SKIP_TIME_MS = 10 * 1000;
    private final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
    private final EmbeddedMediaPlayer mediaPlayer;
    private final Client dirhost;
    private JLabel timeLabel;
    private JProgressBar positionProgressBar;
    private JSlider positionSlider;
    private JLabel durationLabel;
    private JButton stopButton;
    private JButton playButton;
    private JButton toggleMuteButton;
    private JSlider volumeSlider;
    private JButton ejectButton;
    private JButton connectButton;
    private JButton fullScreenButton;
    private JButton timerButton;
    private JComboBox qChanger;
    private Vector<String> qualities;
    private boolean setPositionValue;
    private boolean isNewVideoLoaded;
    private boolean isVideoLoaded;
    private boolean flag;           // Bandera para conocer el estado de la reproduccion: false:video detenido, true: video en reproduccion
    private boolean flag_quality;   // Bandera para detener los cambios de calidad
    private long timer = 0;
    private boolean isChangedByProgram = false;

    public PlayerControlsPanel(EmbeddedMediaPlayer mediaPlayer, Client dirhost) {
        this.mediaPlayer = mediaPlayer;
        this.dirhost = dirhost;
        createUI();
        executorService.scheduleAtFixedRate(new UpdateRunnable(mediaPlayer), 0L, 1L, TimeUnit.SECONDS);
    }

    private void createUI() {
        createControls();
        layoutControls();
        registerListeners();
    }

    private void createControls() {
        timeLabel = new JLabel("hh:mm:ss");
        positionProgressBar = new JProgressBar();
        positionProgressBar.setMinimum(0);
        positionProgressBar.setMaximum(1000000);
        positionProgressBar.setValue(0);
        positionProgressBar.setToolTipText("Time");
        positionProgressBar.setBackground(Color.GRAY);
        //positionProgressBar.setBounds(20, 35, 260, 20);

        positionSlider = new JSlider();
        positionSlider.setMinimum(0);
        positionSlider.setMaximum(1000000);
        positionSlider.setValue(0);
        positionSlider.setToolTipText("Position");

        durationLabel = new JLabel("hh:mm:ss");

        qualities = new Vector<String>();
        qualities.add(ULQ);
        qualities.add(LQ);
        qualities.add(SQ);
        qualities.add(HQ);

        stopButton = new JButton();
        stopButton.setEnabled(false);
        stopButton.setIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/control_stop_blue.png")));
        stopButton.setToolTipText("Detener");

        playButton = new JButton();
        playButton.setEnabled(false);
        playButton.setIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/control_play_blue.png")));
        playButton.setToolTipText("Reproducir");

        toggleMuteButton = new JButton();
        toggleMuteButton.setIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/sound_on.png")));
        toggleMuteButton.setToolTipText("Mute");

        volumeSlider = new JSlider();
        volumeSlider.setOrientation(JSlider.HORIZONTAL);
        volumeSlider.setMinimum(LibVlcConst.MIN_VOLUME);
        volumeSlider.setMaximum(LibVlcConst.MAX_VOLUME);
        volumeSlider.setPreferredSize(new Dimension(100, 40));
        volumeSlider.setToolTipText("Volumen");

        ejectButton = new JButton();
        ejectButton.setEnabled(false);
        ejectButton.setIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/control_eject_blue.png")));
        ejectButton.setToolTipText("Cargar video");

        connectButton = new JButton();
        connectButton.setIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/connect.png")));
        connectButton.setToolTipText("Conectar con el servidor");


        timerButton = new JButton();
        timerButton.setEnabled(false);
        timerButton.setIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/timer.png")));
        timerButton.setToolTipText("Cambiar posición");

        fullScreenButton = new JButton();
        fullScreenButton.setIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/image.png")));
        fullScreenButton.setToolTipText("Pantalla completa");

        qChanger = new JComboBox(qualities);
        qChanger.setToolTipText("Cambiar calidad");
        qChanger.setEnabled(false);


    }

    private void layoutControls() {

        setBorder(new EmptyBorder(4, 4, 4, 4));
        setLayout(new BorderLayout());
        JPanel positionPanel = new JPanel();
        positionPanel.setLayout(new GridLayout(1, 1));//(2,1)
        //positionPanel.add(positionProgressBar);
        positionPanel.add(positionSlider);

        JPanel topPanel = new JPanel();
        topPanel.setLayout(new BorderLayout(8, 0));

        topPanel.add(timeLabel, BorderLayout.WEST);
        topPanel.add(positionPanel, BorderLayout.CENTER);
        topPanel.add(durationLabel, BorderLayout.EAST);

        add(topPanel, BorderLayout.NORTH);

        JPanel bottomPanel = new JPanel();

        bottomPanel.setLayout(new FlowLayout());

        bottomPanel.add(playButton);
        bottomPanel.add(stopButton);
        bottomPanel.add(toggleMuteButton);
        bottomPanel.add(volumeSlider);
        bottomPanel.add(ejectButton);
        bottomPanel.add(connectButton);
        bottomPanel.add(timerButton);
        bottomPanel.add(qChanger);
        bottomPanel.add(fullScreenButton);
        add(bottomPanel, BorderLayout.WEST);
    }

    public void reset() {

        // Deshabilita los botones correspondientes
        ejectButton.setEnabled(false);
        playButton.setEnabled(false);
        stopButton.setEnabled(false);
        qChanger.setEnabled(false);
        // Cierra conexiones abiertas anteriormente
        if (dirhost.getStatus() == 1) {
            mediaPlayer.stop();
            playButton.setIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/control_play_blue.png")));
            dirhost.send_request(STOP);
            dirhost.send_request(QUIT);
            dirhost.close_connection();
            dirhost.setStatus(2);
        }

    }

    public void disableButtons() {
        playButton.setEnabled(false);
        stopButton.setEnabled(false);
        qChanger.setEnabled(false);
        if (dirhost.getStatus() == 1) {
            mediaPlayer.stop();
            playButton.setIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/control_play_blue.png")));
            dirhost.send_request(STOP);
        }
    }

    public void action_stop() {
        mediaPlayer.stop();
        playButton.setIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/control_play_blue.png")));
        dirhost.send_request(STOP);
        flag = false;
        isVideoLoaded = false; //AGREGADO
        updateTime(0);
        timer = 0;
    }

    public void action_play() {
        if (mediaPlayer.isPlaying()) {
            playButton.setIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/control_play_blue.png")));
            mediaPlayer.pause();
            dirhost.send_request(PAUSE);
            flag = false;
            isVideoLoaded = false; //AGREGADO
        } else {
            playButton.setIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/control_pause_blue.png")));
            dirhost.send_request(PLAY);
            mediaPlayer.play();
            isVideoLoaded = true; //AGREGADO
            flag = true;
        }
    }

    private void registerListeners() {
        mediaPlayer.addMediaPlayerEventListener(new MediaPlayerEventAdapter() {

            @Override
            public void playing(MediaPlayer mediaPlayer) {
                updateVolume(mediaPlayer.getVolume());
            }
        });

        positionSlider.addChangeListener(new ChangeListener() {

            @Override
            public void stateChanged(ChangeEvent e) {
                if (!positionSlider.getValueIsAdjusting() && !setPositionValue ) {
                    isVideoLoaded = false;
                    float positionValue = (float) positionSlider.getValue() / 1000000.0f;
                    mediaPlayer.stop();
                    dirhost.send_request(SPOSITION+" "+positionValue);
                    if (flag) {
                        dirhost.send_request(PLAY);
                        mediaPlayer.play();
                        isVideoLoaded = true;
                    }                 
                    

                }/*else if (positionSlider.getValueIsAdjusting() && !setPositionValue && !isChangedByProgram) {

                    float positionValue = (float) positionSlider.getValue() / 1000000.0f;
                    
                //mediaPlayer.setPosition(positionValue);
                System.out.println(positionValue);
                //dirhost.send_request(POSITION+" "+getTime((long)positionValue));

                 }else if(positionChanged){
                float positionValue = (float) positionSlider.getValue() / 1000000.0f;
                dirhost.send_request(SPOSITION+" "+positionValue);
                mediaPlayer.setPosition(positionValue);
                System.out.println(positionValue);
                positionChanged = false;
                }*/
            }
        });

        stopButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                action_stop();
            }
        });

        playButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                action_play();
            }
        });

        toggleMuteButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                if (mediaPlayer.isMute()) {
                    toggleMuteButton.setIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/sound_on.png")));
                    mediaPlayer.mute(false);
                } else {
                    toggleMuteButton.setIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/sound_mute.png")));
                    mediaPlayer.mute(true);
                }
            }
        });

        volumeSlider.addChangeListener(new ChangeListener() {

            @Override
            public void stateChanged(ChangeEvent e) {
                JSlider source = (JSlider) e.getSource();
                if (!source.getValueIsAdjusting()) {
                    mediaPlayer.setVolume(source.getValue());
                }
            }
        });

        ejectButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                mediaPlayer.enableOverlay(false);
                String mediaUrl = (String) JOptionPane.showInputDialog(
                        PlayerControlsPanel.this, "Ingresa el nombre del video:",
                        "Datos del video", JOptionPane.QUESTION_MESSAGE);
                boolean repeat = true;
                if (mediaUrl == null) {
                    repeat = false;
                }
                while (repeat) {
                    if (mediaUrl != null && mediaUrl.length() > 0) {
                        dirhost.send_request(NEWVIDEO + " " + mediaUrl);
                        String response; 
                        qualities = new Vector<String>();
                        boolean b = true;
                        qChanger.removeAllItems();
                        while(b){
                            response = dirhost.get_response();
                            
                            if(response.equals("."))
                                b=false;
                            else{
                                qualities.add(response);
                                qChanger.addItem(response);
                            }
                            
                        }
                        

                        response = dirhost.get_response();
                        if (response.equals(OK)) {
                            flag_quality = false;
                            mediaPlayer.stop();
                            playButton.setEnabled(true);
                            stopButton.setEnabled(true);
                            timerButton.setEnabled(true);
                            
                            qChanger.setEnabled(true);
                            mediaPlayer.playMedia("rtp://@" + dirhost.getHost() + ":" + dirhost.getPort());
                            mediaPlayer.play();
                            isNewVideoLoaded = true;
                            isVideoLoaded = true;
                            playButton.setIcon(new ImageIcon(getClass().getClassLoader().getResource("icons/control_pause_blue.png")));
                            qChanger.setSelectedIndex(0);
                            repeat = false;
                            flag = true;
                            flag_quality = true;
                        } else {
                            disableButtons();
                            mediaUrl = (String) JOptionPane.showInputDialog(
                                    PlayerControlsPanel.this, "Video no válido."
                                    + "\nIngresa el nombre del video:",
                                    "Datos del video", JOptionPane.QUESTION_MESSAGE);
                        }
                    } else if (mediaUrl == null) {
                        repeat = false;
                    } else {
                        mediaUrl = (String) JOptionPane.showInputDialog(
                                PlayerControlsPanel.this, "Ingresa el nombre del video:",
                                "Datos del video", JOptionPane.QUESTION_MESSAGE);
                    }
                }
                mediaPlayer.enableOverlay(false);
         
                //mediaPlayer.setFullScreen(true);
            }
        });



        connectButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                //mediaPlayer.enableOverlay(false);
                isNewVideoLoaded = false;
                isVideoLoaded = false;
                boolean repeat = true;
                //Solicita los datos del servidor y puerto al usuario
                String mediaUrl = (String) JOptionPane.showInputDialog(
                        PlayerControlsPanel.this, "Ingresa servidor:puerto",
                        "Datos de conexión", JOptionPane.QUESTION_MESSAGE);
                //Si presiona cancelar no sucede nada
                if (mediaUrl == null) {
                    repeat = false;
                }
                while (repeat) {
                    //Si presiona aceptar y los datos no son vacios 
                    if (mediaUrl != null && mediaUrl.length() > 0) {
                        //Si existen conexiones cerrarlas
                        reset();
                        StringTokenizer st = new StringTokenizer(mediaUrl, ":");
                        if (st.hasMoreTokens()) {
                            dirhost.setHost(st.nextToken());
                        }
                        if (st.hasMoreTokens()) {
                            dirhost.setPort(Integer.parseInt(st.nextToken()));
                        }
                        //Intenta conectar con los datos proporcionados por el usuario
                        dirhost.open_connection();

                        //Si logra conectar con los datos proporcionados
                        if (dirhost.getStatus() == 1) {
                            // Habilita el boton de ingresar nombre de video 
                            ejectButton.setEnabled(true);
                            repeat = false;
                            //Si no
                        } else {
                            //Solicita los datos nuevamente
                            mediaUrl = (String) JOptionPane.showInputDialog(
                                    PlayerControlsPanel.this, "No fue posible "
                                    + "establecer la conexión.\nIntenta ingresar "
                                    + "servidor:puerto nuevamente",
                                    "Datos de conexión", JOptionPane.QUESTION_MESSAGE);

                        }
                    } else if (mediaUrl == null) {
                        repeat = false;
                    } else {
                        mediaUrl = (String) JOptionPane.showInputDialog(
                                PlayerControlsPanel.this, "Ingresa servidor:puerto",
                                "Datos de conexión", JOptionPane.QUESTION_MESSAGE);
                    }
                }
            }
        });

        timerButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                String time = (String) JOptionPane.showInputDialog(PlayerControlsPanel.this, "Ingresa posición hh:mm:ss", "Posición", JOptionPane.QUESTION_MESSAGE);
                if (time != null && time.length() > 0) {
                    isVideoLoaded = false;
                    mediaPlayer.stop();
                    dirhost.send_request(POSITION + " " + time);
                    if (flag) {
                        dirhost.send_request(PLAY);
                        mediaPlayer.play();
                        isVideoLoaded = true;
                    }
                }
            }
        });

        qChanger.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                if (flag_quality) {
                    isVideoLoaded = false;
                    String quality = (String) ((JComboBox) e.getSource()).getSelectedItem();
                    if(quality==null)
                        quality = ULQ;
                    mediaPlayer.stop();
                    dirhost.send_request(QUALITY + " " + quality);
                    String ok = dirhost.get_response();
                    System.out.println("mande y regreso"+ok);
                    if (ok.equals(OK)) {
                        if (flag) {
                            dirhost.send_request(PLAY);
                            mediaPlayer.play();
                            isVideoLoaded = true;
                        }
                    } else {
                        action_stop();
                        disableButtons();
                        System.out.println("Error ocurrido al momento de configurar la calidad del video.");
                    }
                }
            }
        });

        fullScreenButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                mediaPlayer.toggleFullScreen();
            }
        });
    }

    private final class UpdateRunnable implements Runnable {

        private final MediaPlayer mediaPlayer;
        private long duration = 0;
        private long timer_stop;
        

        private UpdateRunnable(MediaPlayer mediaPlayer) {
            this.mediaPlayer = mediaPlayer;
            this.timer_stop = 0;
        }

        @Override
        public void run() {

            if (isNewVideoLoaded) {
                dirhost.send_request(LENGTH);
                duration = dirhost.get_timer();
                setDuration(duration);
                timer_stop = duration - 1000;
                isNewVideoLoaded = false;
            }
            if (isVideoLoaded) {
                dirhost.send_request(TIMER);
                timer = dirhost.get_timer();
                if (timer >= timer_stop) {
                    action_stop();
                }
                updateTime(timer);
            }
            final int position = duration > 0 ? (int) Math.round(1000000.0 * (double) timer / (double) duration) : 0;
            updatePosition(position);

            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    //updateTime(timer);
                    //updatePosition(position);
                    //updateChapter(chapter, chapterCount);
                }
            });
        }
    }

    private void updateTime(long millis) {
        String s = String.format("%02d:%02d:%02d",
                TimeUnit.MILLISECONDS.toHours(millis),
                TimeUnit.MILLISECONDS.toMinutes(millis) - TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millis)),
                TimeUnit.MILLISECONDS.toSeconds(millis) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis)));
        timeLabel.setText(s);
    }

    private void setDuration(long millis) {
        String s = String.format("%02d:%02d:%02d",
                TimeUnit.MILLISECONDS.toHours(millis),
                TimeUnit.MILLISECONDS.toMinutes(millis) - TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millis)),
                TimeUnit.MILLISECONDS.toSeconds(millis) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis)));
        durationLabel.setText(s);
    }

    private void updatePosition(int value) {
        positionProgressBar.setValue(value);
        // Set the guard to stop the update from firing a change event
        setPositionValue = true;
        positionSlider.setValue(value);
        isChangedByProgram = true;
        setPositionValue = false;
    }

    private void updateVolume(int value) {
        volumeSlider.setValue(value);
    }

    private String getTime(long millis) {
        String s = String.format("%02d:%02d:%02d",
                TimeUnit.MILLISECONDS.toHours(millis),
                TimeUnit.MILLISECONDS.toMinutes(millis) - TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(millis)),
                TimeUnit.MILLISECONDS.toSeconds(millis) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis)));
        return s;
    }
}
